package com.run.runbbs.controller;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.crypto.SecureUtil;
import com.google.code.kaptcha.Producer;
import com.run.runbbs.common.dto.LoginDto;
import com.run.runbbs.common.dto.RegisterDto;
import com.run.runbbs.common.lang.Result;
import com.run.runbbs.entity.User;
import com.run.runbbs.service.impl.UserService;
import com.run.runbbs.util.*;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
public class AccountController {
    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private MailUtils mailUtils;

    @Autowired
    private Producer kaptchaPorducer;

    @Value("${runbbs.upload}")
    private String uploadPath;

    @Value("${runbbs.domain}")
    private String domain;



    private static Logger logger = LoggerFactory.getLogger(AccountController.class);

    @GetMapping("/kaptcha")
    public Result getKaptcha(HttpServletRequest request) throws IOException {
        
        String userIp=HttpUtil.getIpAddress(request);

        /**
         * 前后端分离 登录验证码 方案
         * 后端生成图片 验证码字符串 uuid
         * uuid为key  验证码字符串为value
         * 传递bs64图片 和uuid给前端
         * 前端在登录的时候 传递 账号 密码 验证码 uuid
         * 通过uuid获取 验证码 验证
         */
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        //获取验证码
        String text = kaptchaPorducer.createText();
        logger.info("登录验证码："+text);

        BufferedImage image = kaptchaPorducer.createImage(text);
        ImageIO.write(image, "png", out);
        String base64bytes = Base64.encode(out.toByteArray());

        //该字符串传输至前端放入src即可显示图片，安卓可以去掉data:image/png;base64,
        String src = "data:image/png;base64," + base64bytes;

        Map<String, Object> map = new HashMap<>(2);
        map.put("userIp",userIp);
        map.put("img", src);
        //保存到redis
        String redisKey="kaptcha:"+userIp;
        JedisUtil.setJson(redisKey,text);
        return Result.success(map);

    }


    @PostMapping("/login")
    public Result login(@Validated @RequestBody LoginDto loginDto,HttpServletRequest request, HttpServletResponse response){
        String userIp=HttpUtil.getIpAddress(request);
        String redisCode= JedisUtil.getJson("kaptcha:"+userIp);
        if(!redisCode.equals(loginDto.getCode())){
            return Result.fail("验证码不正确！");
        }

        User user=userService.findUserByName(loginDto.getUsername());
        //断言,如果为空，抛出异常IllegalArgumentException
        Assert.notNull(user,"用户不存在");
        if(!user.getPassword().equals(SecureUtil.md5(loginDto.getPassword()+user.getSalt()))){
            return Result.fail("密码不正确！");
        }
        String jwt=jwtUtils.generateToken(user.getId());
        //将jwt设置到header
        response.setHeader("Authorization",jwt);
        response.setHeader("Access-control-Expose-Headers","Authorization");

        //登录成功，把验证码从reids中删掉
        JedisUtil.delKey("kaptcha:"+userIp);

        return  Result.success(MapUtil.builder()
                .put("userId",user.getId())
                .put("username",user.getUsername())
                .put("email",user.getEmail())
                .put("headerUrl",user.getHeaderUrl())
                .map()
        );
    }

    @RequiresAuthentication
    @GetMapping("/logout")
    public Result logout(){
        //交给shiro作退出。
        SecurityUtils.getSubject().logout();
        return Result.success(null);
    }

    @GetMapping("/getCheckCode")
    public Result getCheckCode(String email){
        User user=userService.findUserByEmail(email);
        if(user!=null){
            return Result.fail("邮箱已存在，请重新输入！");
        }
        String code=mailUtils.sendCodeMail(email);

        //保存到redis,240秒过期
        String redisKey="emailCode:"+email;
        JedisUtil.setJson(redisKey,code,240);

        return  Result.success("获取验证码成功！");
    }


    @PostMapping("/register")
    public Result register(@Validated @RequestBody RegisterDto registerDto, HttpServletResponse response){
        String redisCode= JedisUtil.getJson("emailCode:"+registerDto.getEmail());
        if(redisCode==null||"".equals(redisCode)){
            return Result.fail("验证码已过期！");
        }else if(!redisCode.equals(registerDto.getCode())){
            return Result.fail("验证码不正确！");
        }

        User user=userService.findUserByName(registerDto.getUsername());
        if(user!=null){
            return Result.fail("用户名已存在，请重新输入！");
        }
        user=userService.findUserByEmail(registerDto.getEmail());
        if(user!=null){
            return Result.fail("邮箱已存在，请重新输入！");
        }
        //将用户保存到数据库
        User u=new User();
        u.setUsername(registerDto.getUsername());
        u.setSalt(UUID.randomUUID().toString().substring(0,5));
        u.setPassword(SecureUtil.md5(registerDto.getPassword()+u.getSalt()));
        u.setEmail(registerDto.getEmail());
        u.setType(0);
        u.setStatus(0);
        u.setCreateTime(new Date());
        userService.addUser(u);
        //注册成功，把验证码从reids中删掉
        JedisUtil.delKey("emailCode:"+registerDto.getEmail());
        //注册成功，生成JWT
        String jwt=jwtUtils.generateToken(u.getId());
        //将jwt设置到header
        response.setHeader("Authorization",jwt);
        response.setHeader("Access-control-Expose-Headers","Authorization");

        return  Result.success(MapUtil.builder()
                .put("userId",u.getId())
                .put("username",u.getUsername())
                .put("email",u.getEmail())
                .put("headerUrl",u.getHeaderUrl())
                .map()
        );
    }

    @GetMapping("/require_role")
    @RequiresRoles("admin")
    public Result requireRole() {
        return Result.success( "You are visiting require_role");
    }

    @RequiresAuthentication
    @PostMapping("/upload")
    public Result uploadHeader(MultipartFile headerImage,int userId){
        if(headerImage==null){
            return Result.fail("您还没有选择图片");
        }
        String fileName=headerImage.getOriginalFilename();
        String suffix=fileName.substring(fileName.lastIndexOf("."));//图片后缀
        if(StringUtil.isBlank(suffix)){
            return Result.fail("图片格式不对");
        }
        //生成随机文件名
        fileName=UUID.randomUUID()+suffix;
        //确定文件存放的路径
        File dest=new File(uploadPath+"/"+fileName);
        try {
            headerImage.transferTo(dest);
        } catch (IOException e) {
            logger.error("上传图片失败"+e.getMessage());

           throw new RuntimeException("上传文件失败，服务器发送异常！"+e);
        }
        //更新当前用户的头像的路径（web访问路径）
        String headerUrl=domain+"/image/"+fileName;
        userService.updateHeader(userId,headerUrl);

        return Result.success(MapUtil.builder()
                .put("headerUrl",headerUrl)
                .map());
    }

//    //读取图片
//    @RequiresAuthentication
//    @GetMapping("/upload/{fileName}")
//    public void getHeader(@PathVariable("fileName") String fileName,HttpServletResponse response){
//        //服务器存放路径
//        fileName=uploadPath+"/"+fileName;
//        //文件后缀
//        String suffix=fileName.substring(fileName.lastIndexOf("."));
//        //响应图片
//        response.setContentType("image/"+suffix);
//        try(OutputStream os=response.getOutputStream();
//            FileInputStream fis=new FileInputStream(fileName);)
//        {
//            byte[] buffer=new byte[1024];
//            int b=0;
//            while((b=fis.read(buffer))!=-1){
//                os.write(buffer,0,b);
//            }
//        }catch (IOException e){
//            logger.error("读取头像失败"+e.getMessage());
//        }
//
//    }
    @RequiresAuthentication
    @PostMapping("/changePassword")
    public Result changePassword(String oldPassword,String newPassword,int userId){
        User user=userService.findUserById(userId);
        if(!user.getPassword().equals(SecureUtil.md5(oldPassword+user.getSalt()))){
            return Result.fail("原密码不正确！");
        }
        userService.updatePassword(userId,SecureUtil.md5(newPassword+user.getSalt()));
        return Result.success("密码修改成功！");

    }

}
